using System;
using System.Collections.Generic;
using Kopernikus.Collections.ThreadSafe;
using Kopernikus.Parsing.GenericLexing;

namespace Kopernikus.Parsing
{
    public class GenericLexer<TLexer, TToken> : ILexer<TToken>
    {
        private static readonly ThreadSafeDictionary<Type, Evaluator<TLexer, TToken>> m_evaluators =
            new ThreadSafeDictionary<Type, Evaluator<TLexer, TToken>>();

        private readonly Evaluator<TLexer, TToken> m_evaluator;

        private GenericLexer(Evaluator<TLexer, TToken> evaluator)
        {
            m_evaluator = evaluator;
        }

        #region ILexer<TToken> Members

        public IEnumerable<TToken> Scan(string input)
        {
            foreach (GenericMatch<TToken> match in m_evaluator.Lexer.Scan(m_evaluator, input))
            {
                yield return match.Value;
            }
        }

        #endregion

        public IEnumerable<GenericMatch<TToken>> GenericScan(string input)
        {
            return m_evaluator.Lexer.Scan(m_evaluator, input);
        }

        public static GenericLexer<TLexer, TToken> Create(TLexer instance)
        {
            Evaluator<TLexer, TToken> evaluator =
                m_evaluators.GetValue(instance.GetType(),
                                      delegate(Type t) { return new Evaluator<TLexer, TToken>(t); }).Clone(
                    instance);
            return new GenericLexer<TLexer, TToken>(evaluator);
        }
    }
}